﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System;
using System.Collections.Generic;
using System.Net;
using ScrumTable.Common;
using ScrumTable.Common.Logging;
using ScrumTable.Common.Net;
using ScrumTable.Common.Security;
using ScrumTable.DL.Data.TFS.Properties;

#endregion

namespace ScrumTable.DL.Data.TFS.Services.SharePoint
{
    /// <summary>
    /// This class is used in order to connect to the Microsoft
    /// Windows SharePoint and its lists.
    /// </summary>
    /// <remarks>
    /// All operations on this instance will invoke the underlying WSS
    /// instance.
    /// </remarks>
    public class WssContext
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        private const string MemberFormat = @"{0}\{1}";

        private readonly ServiceRegistration _wssServiceReg;
        private readonly WssIterationList _iterationList;
        private string _iterationListVersion;
        private readonly WssUserList _userList;
        private string _userListVersion;
        private volatile bool _isConnected = false;
        private volatile bool _connectionChecked = false;

        private IDictionary<string, WssUser> _users;
        private IDictionary<int, WssIteration> _iterations;

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        /// <summary>
        /// Makes sure a connection to the wss service could be established
        /// and the user has the sufficient rights to access data on it.
        /// </summary>
        /// <returns>Returns true if the connection succeeded.</returns>
        public bool IsConnected
        {
            get
            {
                if (CanConnect)
                {
                    try
                    {
                        if (!_connectionChecked)
                        {
                            _connectionChecked = true;
                            EnsureConnected();
                        }
                    }
                    catch (WebException e)
                    {
                        Logger<WssContext>.Warn(Resources.ExcWssAuthentication, e);
                    }
                    return _isConnected;
                }
                return false;
            }
        }

        /// <summary>
        /// Returns true if the WssContext can connect to a back-end system.
        /// This is true if the underlying TFS has returned a WSS portal uri.
        /// </summary>
        private bool CanConnect
        {
            get { return _wssServiceReg.HasServiceUri; }
        }

        /// <summary>
        /// Retreives all users from the underlying sharepoint dictionary indexed by its ID.
        /// </summary>
        private IDictionary<string, WssUser> Users
        {
            get
            {
                if (_users == null)
                    _users = _userList.Get(_wssServiceReg.PortalUri);
                return _users;
            }
        }

        /// <summary>
        /// Retreives all users from the underlying sharepoint dictionary indexed by TfsID.
        /// </summary>
        private IDictionary<int, WssIteration> Iterations
        {
            get
            {
                if (_iterations == null)
                    _iterations = _iterationList.Get(_wssServiceReg.PortalUri);
                return _iterations;
            }
        }

        #endregion

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        /// <summary>
        /// Creates a new WssContext instance. This constructor is used in
        /// the current library only.
        /// </summary>
        public WssContext(ServiceRegistration wssUri, ConnectionInformation connectionCtx)
        {
            PreCondition.AssertNotNull(wssUri, "wssUri");
            PreCondition.AssertNotNull(connectionCtx, "connectionCtx");

            _wssServiceReg = wssUri;
            _iterationList = new WssIterationList(connectionCtx);
            _userList = new WssUserList(connectionCtx);
        }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Gets the iteration information of the underlying WSS iteration instance.
        /// </summary>
        /// <param name="iterationId">Id (tfs) of the underlying iteration to retrieve.</param>
        /// <param name="iterationName">Name of the iteration to retrieve.</param>
        /// <returns>Returns the retrieved iteration instance.</returns>
        public WssIteration GetIterationOrDefault(int iterationId, string iterationName)
        {
            if (IsConnected && Iterations.ContainsKey(iterationId))
            {
                return Iterations[iterationId];
            }
            return new WssIteration(iterationId, iterationName);
        }

        /// <summary>
        /// Gets the iteration information of the underlying WSS iteration instance.
        /// </summary>
        /// <param name="iterationId">Id (tfs) of the underlying iteration to retrieve.</param>
        /// <param name="iterationName">Name of the iteration to retrieve.</param>
        /// <returns>Returns the retrieved iteration instance.</returns>
        public WssIteration GetIterationOrCreate(int iterationId, string iterationName)
        {
            if (IsConnected)
            {
                if (Iterations.ContainsKey(iterationId))
                {
                    return Iterations[iterationId];
                }
                else
                {
                    WssIteration iteration = new WssIteration(iterationId, iterationName);
                    AddIteration(iteration);
                    return iteration;
                }
            }
            return new WssIteration(iterationId, iterationName);
        }

        /// <summary>
        /// Gets the user information of the underlying WSS user instance.
        /// </summary>
        /// <param name="accountName">Name of the user to retrieve.</param>
        /// <param name="domainName">Domain of the user to retrieve.</param>
        /// <returns>Returns the retrieved account or a null reference, if it could not be found.</returns>
        public WssUser GetUserOrDefault(string accountName, string domainName)
        {
            string userName = string.Format(
                MemberFormat,
                domainName,
                accountName).ToLowerInvariant();

            if (IsConnected && Users.ContainsKey(userName))
            {
                return Users[userName];
            }
            return new WssUser(accountName, string.Empty);
        }

        /// <summary>
        /// Updates the given element to the underlying list.
        /// </summary>
        /// <param name="toUpdate">Iteration element to update.</param>
        public void UpdateIteration(WssIteration toUpdate)
        {
            _iterationList.Update(_wssServiceReg.PortalUri, _iterationListVersion, toUpdate);
        }

        /// <summary>
        /// Adds the given element to the underlying list.
        /// </summary>
        /// <param name="toAdd">Iteration element to add.</param>
        /// <return>Returns the created id.</return>
        public void AddIteration(WssIteration toAdd)
        {
            _iterationList.Add(_wssServiceReg.PortalUri, _iterationListVersion, toAdd);
        }

        private void EnsureConnected()
        {
            if (!_isConnected)
            {
                _iterationListVersion = _iterationList.Connect(_wssServiceReg.PortalUri);
                _userListVersion = _userList.Connect(_wssServiceReg.PortalUri);

                if (string.IsNullOrEmpty(_iterationListVersion) || string.IsNullOrEmpty(_userListVersion))
                {
                    Logger<WssContext>.Warn(Resources.ExcWssContextInitialization);
                }
                else
                {
                    _isConnected = true;
                }
            }
        }

        #endregion

        #region Events
        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------

        #endregion
    }
}
